package org.shagin.jfin.ui.budget.tree;

import java.awt.event.ContainerAdapter;
import java.awt.event.ContainerEvent;

import javax.swing.JTree;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import org.shagin.jfin.core.Debug;
import org.shagin.jfin.data.model.IBudget;
import org.shagin.jfin.model.event.BudgetAdapter;
import org.shagin.jfin.model.event.BudgetEvent;
import org.shagin.jfin.model.event.OperationCategoryEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The Class BudgetTree.
 */
public class BudgetTree extends JTree {

    private static final long serialVersionUID = -3379477516803736760L;
    private static final Logger log = LoggerFactory.getLogger(BudgetTree.class);

    private IBudget budget;
    private BudgetTreeModel budgetTreeModel;
    private ViewBudgetListener viewBudgetListener = new ViewBudgetListener();

    private class ViewBudgetListener extends BudgetAdapter {

        /**
         * {@inheritDoc}
         */
        @Override
        public void changed(BudgetEvent e) {
            Debug.traceEnter(log);
            updateUI();
            // Add, since componentRemoved event occurs after updateUI().
            addEventListeners();
            Debug.traceLeave(log);
        }

        @Override
        public void operationCategoryAdded(OperationCategoryEvent e) {
            refreshUI();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void operationCategoryDeleted(OperationCategoryEvent e) {
            refreshUI();
        }
    }

    private class ViewContainerListener extends ContainerAdapter {

        /**
         * {@inheritDoc}
         */
        @Override
        public void componentRemoved(ContainerEvent e) {
            Debug.traceEnter(log);
            removeEventListeners();
        }
    }

    /**
     * Instantiates a new budget tree.
     * 
     * @param budget the budget
     */
    public BudgetTree(IBudget budget) {
        super();
        Debug.traceEnter(log);
        if (budget == null)
            throw new IllegalArgumentException();
        setBudget(budget);
        setEditable(true);
        getSelectionModel().setSelectionMode(
                TreeSelectionModel.SINGLE_TREE_SELECTION);
        setShowsRootHandles(true);
        addContainerListener(new ViewContainerListener());
    }

    /**
     * Gets the budget.
     * 
     * @return the budget
     */
    public IBudget getBudget() {
        return budget;
    }

    /**
     * Sets the budget.
     * 
     * @param budget the new budget
     */
    public void setBudget(IBudget budget) {
        Debug.traceEnter(log);
        removeEventListeners();
        this.budget = budget;
        budgetTreeModel = new BudgetTreeModel(budget);
        setModel(budgetTreeModel);
        for (TreeModelListener l : listenerList
                .getListeners(TreeModelListener.class)) {
            budgetTreeModel.addTreeModelListener(l);
        }
        addEventListeners();
    }

    /**
     * Refresh ui.
     */
    private void refreshUI() {
        Debug.traceEnter(log);
        TreePath treePath  = getSelectionPath();
        setBudget(getBudget());
        setSelectionPath(treePath);
    }

    /**
     * Adds the tree model listener.
     * 
     * @param l the l
     */
    public void addTreeModelListener(TreeModelListener l) {
        Debug.traceEnter(log);
        listenerList.add(TreeModelListener.class, l);
        budgetTreeModel.addTreeModelListener(l);
    }

    /**
     * Removes the events.
     */
    private void removeEventListeners() {
        Debug.traceEnter(log);
        if (budget != null) {
            budget.removeBudgetListener(viewBudgetListener);
        }
    }

    /**
     * Adds the events.
     */
    private void addEventListeners() {
        Debug.traceEnter(log);
        if (this.budget != null)
            budget.addBudgetListener(viewBudgetListener);
    }
}
